/*
 * Copyright (C) 2012  Romain DUBOIS
 * 
 * This file is part of NeMoS - Network and Modular Software
 * 
 * NeMoS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * NeMoS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with NeMoS.  If not, see <http://www.gnu.org/licenses/>.
 */
package nemos.remote.rsa.data;

import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.osgi.service.remoteserviceadmin.ExportReference;
import org.osgi.service.remoteserviceadmin.ImportReference;

/**
 * ReferenceImpl : The common {@link ExportReference} and
 * {@link ImportReference} implementation.
 * 
 * @param <T>
 *            The second object type
 * @param <R>
 *            The registration type
 * 
 * @author Romain DUBOIS
 */
public abstract class ReferenceImpl<T, R> {

    /** The endpoint description */
    private EndpointDescription mEndpoint;
    /** The other handled object */
    private T mObject;

    /** The number of registrations currently opened for this endpoint */
    private int mRegistrationCount;
    /** The registration listener */
    private final IUnregistrationListener mListener;

    /**
     * Constructor
     * 
     * @param pEndpoint
     *            The endpoint description
     * @param pObject
     *            The other handled object
     * @param pListener
     *            The listener to notify
     */
    public ReferenceImpl(final EndpointDescription pEndpoint, final T pObject,
            final IUnregistrationListener pListener) {
        super();

        mObject = pObject;
        mEndpoint = pEndpoint;
        mRegistrationCount = 0;
        mListener = pListener;
    }

    /**
     * Get the endpoint description.
     * 
     * @return The endpoint description
     */
    public EndpointDescription getEndpoint() {
        return mEndpoint;
    }

    /**
     * Get the other handled object.
     * 
     * @return The other handled object
     */
    public T getObject() {
        return mObject;
    }

    /**
     * A registration is closing.
     */
    public synchronized void registrationClosed() {
        mRegistrationCount--;
        if (mRegistrationCount == 0) {
            mEndpoint = null;
            mObject = null;
        }
        if (mListener != null) {
            notify(mListener);
        }
    }

    /**
     * Open a new registration.
     * 
     * @return A new registration, or {@code null} if service is no longer
     *         exported.
     */
    public synchronized R openRegistration() {
        if (mEndpoint != null) {
            mRegistrationCount++;
            return createRegistration();
        }
        return null;
    }

    /**
     * Test if service is still exported.
     * 
     * @return If the reference is still active.
     */
    public synchronized boolean isActive() {
        return mEndpoint != null;
    }

    /**
     * Create a new registration.
     * 
     * @return The new registration
     */
    protected abstract R createRegistration();

    /**
     * Notify the registration listener.
     * 
     * @param pListener
     *            The listener to notify
     */
    protected abstract void notify(IUnregistrationListener pListener);
}
